package com.amigo.online.provider.user.service.impl;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import com.amigo.online.common.param.result.VipInfo;
import com.amigo.online.provider.user.service.VIPService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.amigo.online.common.base.security.LocalUser;
import com.amigo.online.common.param.RedisKey;
import com.amigo.online.common.param.result.LocalUserInfo;
import com.amigo.online.common.param.result.UserInfo;
import com.amigo.online.common.util.StringUtils;
import com.amigo.online.provider.user.common.RwRedisService;
import com.amigo.online.provider.user.mapper.UserMapper;
import com.amigo.online.provider.user.mongo.dao.UserDao;
import com.amigo.online.provider.user.service.TokenManagerService;
import com.amigo.online.provider.user.util.ConvertUtil;


@Service
public class TokenManagerServiceImpl implements TokenManagerService {

    private static final Logger logger = LoggerFactory.getLogger(TokenManagerServiceImpl.class);

    @Resource
    private UserMapper userMapper;

    @Autowired
    RwRedisService rwRedisService;

    @Autowired
    UserDao userDao;

    @Autowired
    VIPService vipService;

    @Override
    public String createToken(UserInfo user) {
        LocalUserInfo info = new LocalUserInfo();
        String token = StringUtils.createUserToken();
        //加上VIP信息
        VipInfo vipInfo = vipService.getVipInfo(user.getId());
        user.setVip(vipInfo.isVip()? 1 :0);
        user.setHonoured(vipInfo.isVip());
        user.setVipEndTime(vipInfo.getEndTime());
        info.setUser(checkNull(user));
        info.setToken(token);
        rwRedisService.opsForValue().set(token, info, 2592000L, TimeUnit.SECONDS);
        return token;
    }

    @Override
    public boolean checkToken(String token) {
        if (StringUtils.isBlank(token)) {
            return false;
        }
        if (!rwRedisService.hasKey(token)) {
//			logger.info("token:{}在redis中不存在",token);
            UserInfo userInfo = ConvertUtil.UserToUserInfo(userMapper.findUserByToken(token));
            if (userInfo == null) {
                logger.info("findUserByToken为null:{}", token);
                return false;
            }
            //加上VIP信息
            VipInfo vipInfo = vipService.getVipInfo(userInfo.getId());

            userInfo.setVip(vipInfo.isVip()? 1 :0);
            userInfo.setHonoured(vipInfo.isVip());
            userInfo.setVipEndTime(vipInfo.getEndTime());

            LocalUserInfo info = new LocalUserInfo();
            info.setUser(checkNull(userInfo));
            info.setToken(token);

            rwRedisService.opsForValue().set(token, info, 2592000L, TimeUnit.SECONDS);
            LocalUser.setUser(info);
        } else {
//			logger.info("token:{}在redis中存在",token);
            rwRedisService.expire(token, 2592000L);
            LocalUserInfo user = (LocalUserInfo) rwRedisService.getThroughWrite(token);
            if (user == null) {
                logger.info("用户token存在:用户信息为null! Token为:" + token);
            }
            LocalUser.setUser(user);
        }
        return true;
    }

    @Override
    public void updateUserMongoInfo(Long id, double[] point) {
        String flag = (String) rwRedisService.get(RedisKey.USER_MONGO_LOCATION_UPDATE + id);
        if (flag == null) {
            Update update = new Update().set("loc.coordinates", Arrays.asList(point));
            userDao.updateUserInfo(id, update);
            rwRedisService.opsForValue().set(RedisKey.USER_MONGO_LOCATION_UPDATE + id, "1", 300L, TimeUnit.SECONDS);
        }
    }

    @Override
    public void updateUser(LocalUserInfo user) {
        if (StringUtils.isBlank(user.getToken())) {
            return;
        }
        if (rwRedisService.hasKey(user.getToken())) {
            rwRedisService.opsForValue().set(user.getToken(), user, 2592000L, TimeUnit.SECONDS);
        }

    }

    @Override
    public void updateUserVipInfo(LocalUserInfo user) {
        if (StringUtils.isBlank(user.getToken())) {
            return;
        }
        //加上VIP信息
        VipInfo vipInfo = vipService.getVipInfo(user.getUser().getId());
        user.getUser().setVip(vipInfo.isVip()? 1 :0);
        user.getUser().setHonoured(vipInfo.isVip());
        user.getUser().setVipEndTime(vipInfo.getEndTime());
        if (rwRedisService.hasKey(user.getToken())) {
            rwRedisService.opsForValue().set(user.getToken(), user, 2592000L, TimeUnit.SECONDS);
        }
        LocalUser.setUser(user);


    }

    private static UserInfo checkNull(UserInfo userInfo) {
        Class<? extends UserInfo> clazz = userInfo.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                String type = field.getType().toString();
                String methodName = field.getName().replaceFirst(field.getName().substring(0, 1),
                        field.getName().substring(0, 1).toUpperCase());
                if (type.endsWith("String")) {
                    // 调用getter方法获取属性值
                    String str = (String) clazz.getMethod("get" + methodName).invoke(userInfo);
                    if (StringUtils.isBlank(str)) {
                        // 如果为null的String类型的属性则重新复制为空字符串
                        field.set(userInfo, "");
                    }
                } else if (type.endsWith("Integer")) {
                    if (clazz.getMethod("get" + methodName).invoke(userInfo) == null) {
                        field.set(userInfo, 0);
                    }
                } else if (!StringUtils.equals(methodName, "SerialVersionUID") && type.endsWith("Long")) {
                    if (clazz.getMethod("get" + methodName).invoke(userInfo) == null) {
                        field.set(userInfo, 0L);
                    }

                } else if (!StringUtils.equals(methodName, "SerialVersionUID") && type.endsWith("Double")) {
                    if (clazz.getMethod("get" + methodName).invoke(userInfo) == null) {
                        field.set(userInfo, 0D);
                    }

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return userInfo;
    }


}
